


var defaultValue = Cesium.defaultValue;
var SceneMode = Cesium.SceneMode;



function RadarSensorPrimitive(options) {
    options = defaultValue(options, defaultValue.EMPTY_OBJECT);
    this.show = defaultValue(options.show, true);
    this.modelMatrix = Cesium.Matrix4.clone(options.modelMatrix, new Cesium.Matrix4());
    this._modelMatrix = new Cesium.Matrix4();
    // 面颜色
    this.color = defaultValue(options.color, Cesium.Color.WHITE);
    this._color = Cesium.Color.WHITE;
    // 线颜色
    this.lineColor = defaultValue(options.lineColor, Cesium.Color.WHITE);
    this._lineColor = Cesium.Color.WHITE;
    // 方位角起
    this.AzimuthFrom = defaultValue(options.AzimuthFrom, 0);
    this._AzimuthFrom = 0;
    // 方位角止
    this.AzimuthTo = defaultValue(options.AzimuthTo, 0);
    this._AzimuthTo = 0;
    // 俯仰角起
    this.ElevationFrom = defaultValue(options.ElevationFrom, 0);
    this._ElevationFrom = 0;
    // 俯仰角止
    this.ElevationTo = defaultValue(options.ElevationTo, 0);
    this._ElevationTo = 0;
    // 半径
    this.radius = defaultValue(options.radius, 0);
    this._radius = 0;
    // 渲染间隔
    this.slice = defaultValue(options.AzimuthFrom, 60);
    this._slice = 60;

    this._Angle = 0;


    this.vs = `
    attribute vec4 position;
    attribute vec3 normal;
    
    varying vec3 v_position;
    varying vec3 v_positionWC;
    varying vec3 v_positionEC;
    varying vec3 v_normalEC;
    
    void main()
    {
        gl_Position = czm_modelViewProjection * position;
        v_position = vec3(position);
        v_positionWC = (czm_model * position).xyz;
        v_positionEC = (czm_modelView * position).xyz;
        v_normalEC = czm_normal * normal;
    }`;
    this.fs = this.renderFS();
}
RadarSensorPrimitive.prototype.renderFS = function (color) {
    if (!color) color = Cesium.Color.WHITE;
    return `void main(){gl_FragColor=vec4(${color.red},${color.green},${color.blue},${color.alpha});}`;
}
RadarSensorPrimitive.prototype.isDestroyed = function () {
    return false
}
RadarSensorPrimitive.prototype.destroy = function () {

}
RadarSensorPrimitive.prototype.update = function (frameState) {
    var mode = frameState.mode;
    if (!this.show || mode !== SceneMode.SCENE3D) {
        return;
    }
    var isRender = false;
    if (this.color) {
        if (!this.color.equals(this._color)) {
            isRender = true;
            this._color = this.color;
            this.fs = this.renderFS(this._color);
        };
    }

    if (this.lineColor) {
        if (!this.lineColor.equals(this._lineColor)) {
            isRender = true;
            this._lineColor = this.lineColor;
            this.fs_lineColor = this.renderFS(this._lineColor);
        };
    }
    if (this.modelMatrix != this._modelMatrix) {
        isRender = true;
        this._modelMatrix = this.modelMatrix;
    };


    if (this.AzimuthFrom != this._AzimuthFrom) {
        isRender = true;
        this._AzimuthFrom = this.AzimuthFrom;
        this._Angle = this._AzimuthFrom;

    }

    if (this.AzimuthTo != this._AzimuthTo) {
        isRender = true;
        this._AzimuthTo = this.AzimuthTo;
        this._Angle = this._AzimuthFrom;

    }
    if (this.ElevationFrom != this._ElevationFrom) {
        isRender = true;
        this._ElevationFrom = this.ElevationFrom;
    }
    if (this.ElevationTo != this._ElevationTo) {
        isRender = true;
        this._ElevationTo = this.ElevationTo;
    }
    if (this.radius != this._radius) {
        isRender = true;
        this._radius = this.radius;
    }
    if (this.slice != this._slice) {
        isRender = true;
        this._slice = this.slice;
    }

    if (Math.abs(this._ElevationTo - this._ElevationFrom) < this.slice) {
        this._slice = this.slice = Math.abs(this._ElevationTo - this._ElevationFrom)
    }

    if (Math.abs(this._AzimuthTo - this._AzimuthFrom) < this.slice) {
        this._slice = this.slice = Math.abs(this._AzimuthTo - this._AzimuthFrom)
    }

    if (isRender) this._Point = createVertexArray(this._AzimuthFrom, this._AzimuthTo, this._ElevationFrom, this._ElevationTo, this._radius, this._slice);

    this._Angle += (this._AzimuthTo - this._AzimuthFrom) / 200;
    if (this._Angle > this._AzimuthTo) {
        this._Angle = this._AzimuthFrom;
    } else if (this._Angle < this._AzimuthFrom) {
        this._Angle = this._AzimuthFrom;
    }
    var _ScanPlane = ScanPlanePoint(this._Angle, this._ElevationFrom, this._ElevationTo, this._radius, this._slice);

    var commandList = frameState.commandList
    var pointCommand = getCommand(this.vs, this.fs, frameState, this._Point.area, this._modelMatrix, false);
    commandList.push(pointCommand);
    var pointCommand = getCommand(this.vs, this.fs, frameState, _ScanPlane, this._modelMatrix, false);
    commandList.push(pointCommand);
    var pointCommand = getCommand(this.vs, this.fs_lineColor, frameState, this._Point.line, this._modelMatrix, true);
    commandList.push(pointCommand);
}

var CX = function (radius, angle) {
    return radius * Math.cos(angle * Math.PI / 180);
}
var CY = function (radius, angle) {
    return radius * Math.sin(angle * Math.PI / 180);
}


var unit = (Star, End, slice) => (End - Star) / Math.ceil(((End - Star) / slice));




// 顶面/底面 扇形点集渲染
var sector = (point, Ans) => {
    for (let i = 0; i < point.length - 1; i++) {
        Ans.push(0, 0, 0);
        Ans.push.apply(Ans, point[i]);
        Ans.push.apply(Ans, point[i + 1]);
    }
};


// 侧面
var side = (point, Ans) => {
    for (let i = 0; i < point.length - 1; i++) {
        var thisP = point[i];
        var LastP = point[i + 1];

        Ans.push(0, 0, 0);
        Ans.push.apply(Ans, thisP[0]);
        Ans.push.apply(Ans, LastP[0]);

        Ans.push(0, 0, 0);
        Ans.push.apply(Ans, thisP[thisP.length - 1]);
        Ans.push.apply(Ans, LastP[LastP.length - 1]);
    }
}

// 曲面
var topface = (point, Ans) => {
    for (let i = 0; i < point.length - 1; i++) {
        const ThisLine = point[i];
        const NextLine = point[i + 1];
        for (let d = 0; d < ThisLine.length - 1; d++) {
            const ThisLineThisPoint = ThisLine[d];
            const ThisLineNextPoint = ThisLine[d + 1];
            const NextLineThisPoint = NextLine[d];
            const NextLineNextPoint = NextLine[d + 1];

            Ans.push.apply(Ans, ThisLineThisPoint);
            Ans.push.apply(Ans, NextLineThisPoint);
            Ans.push.apply(Ans, NextLineNextPoint);

            Ans.push.apply(Ans, ThisLineThisPoint);
            Ans.push.apply(Ans, ThisLineNextPoint);
            Ans.push.apply(Ans, NextLineNextPoint);
        }
    }
}

// 基础点集
function BaseVertexArray(AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo, radius, slice) {
    var _unit = unit(ElevationFrom, ElevationTo, slice);
    // 定点缓存坐标
    var _point = []
    for (let i = ElevationFrom; i >= ElevationTo; i -= _unit) {
        _point.push(computeRadius(AzimuthFrom, AzimuthTo, i, radius, slice));
    }
    return _point;
}


function CreatrAreaVertexArray(_point, AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo) {
    var point = [];

    if (ElevationFrom != 90) {
        sector(_point[0], point);
    }
    if (ElevationTo != -90) {
        sector(_point[_point.length - 1], point);
    }

    if (Math.abs(AzimuthTo - AzimuthFrom) != 360) {
        // 侧面
        side(_point, point);
    }
    // 曲面
    topface(_point, point);
    return point;
}



// 顶面/底面 线
function LineForSector(point, Ans) {
    // for (let i = 0; i < point.length; i++) {
    //     var thisP = point[i];
    //     Ans.push(0, 0, 0);
    //     Ans.push.apply(Ans, thisP);
    // }

    var FP = point[0];
    Ans.push(0, 0, 0);
    Ans.push.apply(Ans, FP);

    var EP = point[point.length - 1];
    Ans.push(0, 0, 0);
    Ans.push.apply(Ans, EP);

};


function LineForTopface(point, Ans) {
    for (let i = 0; i < point.length; i++) {
        const Line = point[i];
        for (let d = 0; d < Line.length - 1; d++) {
            const thisLine = Line[d];
            const nextLine = Line[d + 1];
            Ans.push.apply(Ans, thisLine);
            Ans.push.apply(Ans, nextLine);
        }
    };

    for (let i = 0; i < point.length - 1; i++) {
        const ThisLine = point[i];
        const NextLine = point[i + 1];
        for (let d = 0; d < ThisLine.length; d++) {
            const thisPoint = ThisLine[d];
            const nextPoint = NextLine[d];
            Ans.push.apply(Ans, thisPoint);
            Ans.push.apply(Ans, nextPoint);
        }
    };
}




function CreatrLineVertexArray(_point, AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo) {
    var point = [];

    if (ElevationFrom != 90 && Math.abs(AzimuthTo - AzimuthFrom) != 360) {
        LineForSector(_point[0], point);
    }
    if (ElevationTo != -90 && Math.abs(AzimuthTo - AzimuthFrom) != 360) {
        LineForSector(_point[_point.length - 1], point);
    }

    // if (Math.abs(AzimuthTo - AzimuthFrom) != 360) {
    //     // 侧面
    //     LineForSide(_point, point);
    // }

    LineForTopface(_point, point);
    return point
}

var computeRadius = function (Star, End, angleY, radius, slice) {
    var point = [];
    // 截面高度
    var height = CY(radius, angleY);
    // 截面半径
    var _R = CX(radius, angleY);
    var _unit = unit(Star, End, slice);
    // 截面点集
    for (let i = Star; i <= End; i += _unit) {
        point.push([CY(_R, i), CX(_R, i), height]);
    }
    if ((End - Star) % unit != 0) {
        point.push([CY(_R, End), CX(_R, End), height]);
    }
    return point;
}


function ScanPlanePoint(Angle, ElevationFrom, ElevationTo, radius, slice) {
    var point = [];
    var _unit = unit(ElevationFrom, ElevationTo, slice);
    // 定点缓存坐标
    var _point = []
    // var X = CX(radius, Angle);
    // // 截面半径
    for (let i = ElevationFrom; i >= ElevationTo; i -= _unit) {
        var height = CY(radius, i);
        var _R = CX(radius, i);
        point.push([CY(_R, Angle), CX(_R, Angle), height]);
    }
    for (let i = 0; i < point.length - 1; i++) {
        var thisP = point[i];
        var LastP = point[i + 1];
        _point.push(0, 0, 0);
        _point.push.apply(_point, thisP);
        _point.push.apply(_point, LastP);
    }
    return _point;
}


function createVertexArray(AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo, radius, slice) {
    var _point = BaseVertexArray(AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo, radius, slice);
    return {
        area: CreatrAreaVertexArray(_point, AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo),
        line: CreatrLineVertexArray(_point, AzimuthFrom, AzimuthTo, ElevationFrom, ElevationTo),
    };
}

//用prototype给定方法和属性
var getCommand = function (v, f, frameState, arr, modelMatrix, isLine) {
    var context = frameState.context;
    //shaderProgram将两个着色器合并
    var shaderProgram = Cesium.ShaderProgram.fromCache({
        context: context,
        vertexShaderSource: v,
        fragmentShaderSource: f
    })
    //渲染状态
    var renderState = Cesium.RenderState.fromCache({
        depthTest: {
            enabled: true
        },
        depthMask: false,
        blending: Cesium.BlendingState.ALPHA_BLEND
    })
    //顶点数组Buffer
    var vertexBuffer = Cesium.Buffer.createVertexBuffer({
        context: context,
        typedArray: Cesium.ComponentDatatype.createTypedArray(
            Cesium.ComponentDatatype.FLOAT,
            arr,
        ),
        usage: Cesium.BufferUsage.STATIC_DRAW
    })
    //用来表示逐个顶点的信息
    var attributes = []
    attributes.push({
        index: 0,
        vertexBuffer: vertexBuffer,
        componentDatatype: Cesium.ComponentDatatype.FLOAT,
        componentsPerAttribute: 3,
        normalize: false
    })
    //顶点数组（设置顶点属性和索引Buffer）
    var vertexArray = new Cesium.VertexArray({
        context: context,
        attributes: attributes,
    })

    //新建一个DrawCommand
    return new Cesium.DrawCommand({
        // 渲染线类型
        // primitiveType: Cesium.PrimitiveType.LINES,
        // 渲染面类型
        primitiveType: isLine ? Cesium.PrimitiveType.LINES : Cesium.PrimitiveType.TRIANGLES,
        shaderProgram: shaderProgram,
        renderState: renderState,
        vertexArray: vertexArray,
        pass: Cesium.Pass.OPAQUE,
        modelMatrix: modelMatrix,
    })
}


export { RadarSensorPrimitive }